<?php

namespace common\helpers\maths;

use yii\base\InvalidConfigException;
use common\helpers\MathHelper;

/**
 * 正态分布计算
 *
 * ```
 * $list = array(1.09,1.50,1.31,1.44);
 * $normdist = new Normdist($list);
 * echo $normdist->getCdf($list[0]);
 * ```
 *
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
class Normdist extends \yii\base\BaseObject {

    public $list = [];
    public $average;
    public $stdDev;

    public function init() {
        if (!empty($this->list)) {
            $this->average = MathHelper::average($this->list);
            $this->stdDev = MathHelper::stdDev($this->list);
        }
        if (!$this->average || !$this->stdDev) {
            throw new InvalidConfigException('Transaction::db must be set.');
        }
    }

    /**
     * @name 正态分布的累积概率函数
     * @param string|integer $value
     * @return number
     */
    public function computed($value) {
        return [
            'value' => $value,
            'average' => $this->average,
            'stdDev' => $this->stdDev,
            'cdf' => $this->cdf($value, $this->average, $this->stdDev),
        ];
    }

    /**
     * @name 正态分布的累积概率函数
     * @param string|integer $value 目标值
     * @param string|integer $average 平均值
     * @param string|integer $stdDev 标准差
     * @return number
     */
    public function cdf($value, $average, $stdDev) {
        $t = $value - $average;
        if ($stdDev === 0) {
            if ($t === 0) {
                return 1;
            }
            return 0;
        }
        $y = $this->erfcc(-$t / ($stdDev * sqrt(2)));
        if ($y > 1) {
            $y = 1;
        }
        return $y;
    }

    /**
     * @name 正态分布的累积概率函数
     * @param string|integer $x
     * @return number
     */
    private function erfcc($x) {
        $z = abs($x);
        $t = 1 / (1 + $z / 2);
        $args = $this->factorial($t);
        $r = $t * exp(-$z * $z + $args) / 2;
        if ($x >= 0) {
            return $r;
        } else {
            return 1 - $r;
        }
    }

    /**
     * @name 正态分布的累积概率函数
     * @param string|integer $t
     * @return number
     */
    private function factorial($t) {
        $data = [
            .17087277,
            -.82215223,
            1.48851587,
            -1.13520398,
            .27886807,
            -.18628806,
            .09678418,
            .37409196,
            1.00002368,
            - 1.26551223
        ];

        $temp = 0;
        foreach ($data as $item) {
            $temp = $t * $temp + $item;
        }
        return $temp;
    }

}
